#!/usr/bin/perl -w

use Switch;
use strict;

# Config
my $cfg;                            # Config file name
my $os="lin";                       # OS name;
my $verbose=0;                      # Whether output operation details, 1=true, 0=false;
my $gc=0;                           # GC to optimize repo performance;
(-e "C:\\") && ($os="win");         # Judge OS;

###############################################################################################
proc_args(\@ARGV);
# parse configuration file to get repo info
my $FILE;
open $FILE,"$cfg"; 
defined($FILE) or die "Fail to open config file $cfg\n";
foreach ( <$FILE>){ $_=~/(\S+)\s+(\S+)/ && !($_=~/^\#/) && update($1,$2); }
close $FILE; 

###############################################################################################
# Method to process arguements;
sub proc_args{
    my ($args)=@_;
    my @bad_args;
    foreach my $arg (@$args) {
        if( not $arg=~/^-/) {
            push @bad_args, $arg;
        } 
        if ( $arg=~/verbose/i) {
            # if verbose enabled from command line;
            $verbose=1;
        }
        if ( $arg=~/cfg=(\S+)/i || $arg=~/cfg=\"(\.+)\"/i) {
            # if config file specified from command line;
            $cfg=$1;
        }
        if ( $arg=~/help/i) {
            show_help();
            exit(-1);
        }
        if ( $arg=~/gc/i) {
            $gc=1;
        }
    }

    if ( not defined($cfg)){
        (($os eq "win") && ($cfg="./hyrepo.conf")) || ($cfg="/etc/hyrepo.conf");
    }
    if( @bad_args >0){
        print "Bad arguements:@bad_args\n";
        show_help();
        exit( -1);
    }
}

###############################################################################################
# Actual updating action to the repositories.  
sub update{ 
    my ($type, $path)=@_; 
    print "[Updating $type repo $path]\n"; 

    switch( $type){ 
        case "svn" {
            chdir $path;
            process_repo("svn up $path", "svn diff", "svn revert . -R");
        } 
        case "git-svn" { 
            chdir $path; 
            process_repo("git svn rebase", "git diff", "git checkout -f");
        }
        case "git" {
            chdir $path;
            process_repo("git pull", "git diff", "git checkout -f");
        }
    }
}

###############################################################################################
#check if error occurs
#   return 0 if no errors, vice versa
sub check_err{
    my ($log)=@_;
    foreach(@$log){
        if($_=~/error/i || $_=~/exception/i){
            return 1;
        }
    }
    return 0;
}

###############################################################################################
# Process each repo;
sub process_repo{
    my ($cmd_up, $cmd_diff, $cmd_revert)=@_;
    print "Trying to update\n \'$cmd_up\'\n";
    ($gc==1) && ($cmd_up=~/^git/i) &&(run_cmd("git gc"));       # Perform gc for git repo;
    my @log=run_cmd("$cmd_up 2>&1");
    if( check_err(\@log)!=0 ){
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
        my $diff="$year-$mon-$mday-$hour-$min-$sec.diff";
        print "Exception detected!\n";
        print "Backing up modifications to $diff and reseting working copy\n"; 
        run_cmd("$cmd_diff >> $diff");
        run_cmd("$cmd_revert");

        print "Try to run \'$cmd_up\' again\n";
        run_cmd("$cmd_up");
    }
}

###############################################################################################
#execute shell command
sub run_cmd{
    my ($cmd)=@_;
    my @log;
    if( $verbose==1){
        @log=system("$cmd");
    }else{
        @log=`$cmd`;
    }
    return @log;
}

###############################################################################################
# Display help information;
sub show_help{
    print "Usage:\n\thygit [option] [option] .. [option]\n";
    print "Available options:\n";
    print "\t-verbose\tOut put detailed operation info\n";
    print "\t-cfg=[filename]\tUse user-specified config file\n";
    print "\t-gc\tPerform gc for git repo before update\n";
    print "\t-help\tShow this help message\n";
    print "Examples:\n";
    print "\thyup -verbose\n";
    print "\thyup -verbose -cfg=/home/user/cfg.list -gc\n";
    print "\n";
}

